// src/core/middleware/file.middleware.js
import multer from "multer";
import fs from "fs";
import path from "path";
import { FileService } from "../../services/file.service.js";
import {
  calculateFileHash,
  calculateLargeFileHash,
} from "../../utils/file-utils.js";
import { BadRequestError } from "../../utils/errors.js";
import { db } from "./../../config/sequelize.js";

const fileService = new FileService(db);

/**
 * 文件上传中间件类
 */
export class UploadMiddleware {
  /**
   * 创建文件记录中间件,用于创建文件记录 ??? 用于单文件上传，多文件上传待定...
   * @param {*} req
   * @param {*} res
   * @param {*} next
   */
  static async createFileRecord(req, res, next) {
    console.log('创建文件记录中间件--req.file', req.file)

    try {
      const file = req.file || (req.files && req.files[0]);

      if (!file) {
        throw new BadRequestError("未收到上传文件");
      }

      const fileHash = req.body.fileHash || req.validatedData?.fileHash;
      console.log("文件哈希--fileHash", fileHash);
      if (!fileHash) {
        // 如果没有提供 fileHash，则计算一个
        try {
          fileHash =
            file.size > 10 * 1024 * 1024
              ? await calculateLargeFileHash(file)
              : await calculateFileHash(file);
        } catch (hashError) {
          throw new BadRequestError(`计算文件哈希失败: ${hashError.message}`);
        }
      }

      // 确保文件名存在
      const fileName = file.originalname || req.body.fileName;
      if (!fileName) {
        throw new BadRequestError("缺少文件名");
      }
      console.log("fileName:", fileName);
      console.log("创建文件记录--fileHash:", fileHash);

      const chunkHash = req.body.chunkHash || req.validatedData?.chunkHash;
      console.log("分片哈希--chunkHash", chunkHash);

      req.fileRecord = await fileService.createFileRecord({
        fileHash,
        fileName,
        chunkHash: chunkHash,
        fileSize: file.size,
        fileType: file.mimetype,
        userId: req.user.id,
        status: "pending",
      });
      // 将 fileHash 添加到 req 对象，供后续中间件使用
      req.generatedFileHash = fileHash;
      next();
    } catch (error) {
      next(error);
    }
  }
/**
 * 验证文件记录
 * @param {*} req 
 * @param {*} res 
 * @param {*} next 
 */
  static async verifyFileRecord(req, res, next) {
  try {
    const { fileHash } = req.body;
    
    // 验证文件记录是否存在
    const record = await fileService.getFileRecord(fileHash);
    if (!record) {
      throw new BadRequestError("请先调用初始化接口创建文件记录");
    }
    
    // 验证状态是否允许上传
    if (record.status !== 'uploading') {
      throw new BadRequestError(`文件当前状态为${record.status}，不允许上传`);
    }
    
    req.fileRecord = record;
    next();
  } catch (error) {
    next(error);
  }
}
  /**
   * 动态生成存储配置
   * @param {string} subDir 子目录名称（如 'thumbnails'）
   */
  static #getStorage(subDir = "") {
    return multer.diskStorage({
      destination: (req, file, cb) => {
        const uploadDir = path.join("uploads", subDir); // 如 uploads/thumbnails
        fs.mkdirSync(uploadDir, { recursive: true }); // 自动创建目录
        cb(null, uploadDir);
      },
      filename: (req, file, cb) => {
        cb(null, `${Date.now()}-${file.originalname}`);
      },
    });
  }
  // 存储配置
  static #storage = multer.diskStorage({
    destination: (req, file, cb) => {
      cb(null, "uploads/");
    },
    filename: (req, file, cb) => {
      cb(null, `${Date.now()}-${file.originalname}`);
    },
  });

  // 文件过滤器
  static #fileFilter = (req, file, cb) => {
    console.log("file类型：", file.mimetype);
    if (
      ["image/jpeg", "image/png", "application/octet-stream"].includes(
        file.mimetype
      )
    ) {
      cb(null, true);
    } else {
      cb(new Error("仅支持 JPG/PNG 格式"), false);
    }
  };

  // 创建 multer 实例
  static #createMulter(config = {}) {
    return multer({
      storage: this.#storage,
      fileFilter: this.#fileFilter,
      limits: { fileSize: 10 * 1024 * 1024 },
    preservePath: true, // 保留临时文件路径
      ...config,
    });
  }

  /**
   * 单文件上传中间件
   * @param {string} fieldName 表单字段名
   * @param {string} subDir 子目录名（可选）
   */
  static single(fieldName, subDir = "") {
    console.log('单文件上传中间件--fieldName', fieldName)

    return (req, res, next) => {
      multer({
        storage: this.#getStorage(subDir),
        fileFilter: this.#fileFilter,
        limits: { fileSize: 10 * 1024 * 1024 },
      }).single(fieldName)(req, res, (err) => {
        if (err) return next(err);
        next();
      });
    };
  }
  /**
   * 多文件上传中间件
   * @param {string} fieldName 表单字段名
   * @param {string} subDir 子目录名（可选）
   * @param {number} maxCount 最大文件数（可选）
   * */

  static multiple(fieldName, subDir = "", maxCount = 10) {
    console.log('多文件上传中间件--fieldName', fieldName)

    return (req, res, next) => {
      // 1. 动态生成存储配置
      const storage = multer.diskStorage({
        destination: (req, file, cb) => {
          const safeSubDir = subDir.replace(/\.\.\//g, ""); // 防止路径遍历攻击
          const uploadDir = path.join("uploads", safeSubDir);

          // 自动创建目录（如果不存在）
          fs.mkdirSync(uploadDir, { recursive: true });
          cb(null, uploadDir);
        },
        filename: (req, file, cb) => {
          const ext = path.extname(file.originalname);
          const sanitizedName = file.originalname
            .replace(ext, "")
            .replace(/[^a-zA-Z0-9_-]/g, "_");
          cb(null, `${Date.now()}-${sanitizedName}${ext}`);
        },
      });

      // 2. 文件类型过滤
      const fileFilter = (req, file, cb) => {
        const allowedTypes = [
          "image/jpeg",
          "image/png",
          "image/webp",
          "application/pdf",
        ];

        if (allowedTypes.includes(file.mimetype)) {
          cb(null, true);
        } else {
          cb(new Error(`不支持的文件类型: ${file.mimetype}`), false);
        }
      };

      // 3. 创建multer实例
      const upload = multer({
        storage,
        fileFilter,
        limits: {
          fileSize: 20 * 1024 * 1024, // 20MB/文件
          files: maxCount, // 最大文件数
        },
      });

      // 4. 处理上传
      upload.array(fieldName, maxCount)(req, res, (err) => {
        if (err) {
          // 错误分类处理
          let message = "文件上传失败";
          if (err.code === "LIMIT_FILE_SIZE") {
            message = `单个文件不能超过20MB`;
          } else if (err.code === "LIMIT_FILE_COUNT") {
            message = `最多允许上传${maxCount}个文件`;
          } else if (err.code === "LIMIT_UNEXPECTED_FILE") {
            message = `字段名必须为'${fieldName}'`;
          }
          return next({ ...err, message });
        }
        next();
      });
    };
  }

  /**
   * 分片上传中间件（允许更大文件）
   * @param {string} fieldName 表单字段名
   */
  static chunk(fieldName) {
    return (req, res, next) => {
      this.#createMulter({ limits: { fileSize: 20 * 1024 * 1024 } }).single(
        fieldName
      )(req, res, (err) => {
        if (err) return next(err);
        next();
      });
    };
  }
}
